#![allow(non_snake_case)]

extern crate actix_web;
extern crate rusqlite;
extern crate serde;
extern crate serde_json;
extern crate futures;
extern crate bytes;
extern crate chrono;
use self::actix_web::{HttpRequest, HttpResponse, Responder,
                Result, error, http::StatusCode, HttpMessage,
                Path, Query, fs::NamedFile, error::Error};
use std::sync::{Mutex, Arc, MutexGuard};
use dragonpak;
use self::futures::Future;
use self::bytes::Bytes;
use std::collections::{HashMap};
extern crate rand;
//use rusqlite::Connection;

//type ArcShareState = Arc<Mutex<rusqlite::Connection>>;
type ArcShareState = Arc<Mutex<dragonpak::ShareState>>;
// article ==============================================

pub fn article_get(req: &HttpRequest<ArcShareState>) -> Result<HttpResponse> {

    let mut sort: String = "latest".to_string();
    let mut start: i32 = 0;
    let mut len: i32 = 10;

    //获取各个参数
    let query = req.query();
    if let Some(v) = query.get(&"sort".to_string()) {
        //println!("{}", v);
        sort = v.clone();
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    if let Some(v) = query.get(&"start".to_string()) {
        //println!("{}", v);
        start = v.parse().or(Err(error::ErrorBadRequest("")))?;
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    if let Some(v) = query.get(&"len".to_string()) {
        //println!("{}", v);
        len = v.parse().or(Err(error::ErrorBadRequest("")))?;
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    //判断排序方式
    let mut order = "DESC".to_string();
    if sort == "latest" {
        order = "DESC".to_string();
    } else if sort == "oldest" {
        order = "ASC".to_string();
    } else {
        Err(error::ErrorBadRequest(""))?
    }


    //获取数据库连接
    let mut conct = &req.state()
        .lock()
        .or(Err(error::ErrorInternalServerError("mutex error")))?
        .connection;

    let query = format!("\
    SELECT id, title, date, poster, intro, class
    FROM article
    ORDER BY id
    {}
    LIMIT {} OFFSET {}
    ", order, len, start);

    //let query = format!(query, order, len, start);

    let mut statement = conct.prepare(&query)
        .or(Err(error::ErrorInternalServerError("prepare error")))?;

    //进行查询
    let rows = statement.query_map(&[], |row| {
        /*
        let id: i64 = row.get(0);
        let title: String = row.get(1);
        let date: i64 = row.get(2);
        let poster: String = row.get(3);
        let intro: String = row.get(4);
        let class: String = row.get(5);

        json!({
            "id": id,
            "title": title,
            "date": date,
            "poster": poster,
            "intro": intro,
            "class": class
        })
        */
        json!({
            "id": row.get::<_, i64>(0),
            "title": row.get::<_, String>(1),
            "date": row.get::<_, i64>(2),
            "poster": row.get::<_, String>(3),
            "intro": row.get::<_, String>(4),
            "class": row.get::<_, String>(5)
        })
    }
        ).or(Err(error::ErrorInternalServerError("query error")))?;

    let mut article_list = vec![];

    //铁代出所有结果
    for r in rows {
        let r = r.or(Err(error::ErrorInternalServerError("")))?;
        article_list.push(r);
    }


    let query = "SELECT COUNT(*) FROM article";
    //查询总数
    let total = conct.query_row(query, &[], |r| r.get::<i32, i32>(0))
        .or(Err(error::ErrorInternalServerError("")))?;

    let result = json!({
        "total": total,
        "count": article_list.len(),
        "article": article_list
    });

    Ok(HttpResponse::build(StatusCode::OK).body(result.to_string()))
}


pub fn article_class_get(req: &HttpRequest<ArcShareState>) -> Result<HttpResponse> {
    let mut conct = &req.state()
        .lock()
        .or(Err(error::ErrorInternalServerError("mutex error")))?
        .connection;


    let query = "\
    SELECT * FROM article_class
    ";

    let mut statement = conct.prepare(query)
        .or(Err(error::ErrorInternalServerError("prepare error")))?;
    let rows = statement.query_map(&[], |row| row.get(0))
        .or(Err(error::ErrorInternalServerError("query error")))?;

    let mut class = vec![];

    for t in rows {
        let name: String = t.or(Err(error::ErrorInternalServerError("get data error")))?;
        //let name: String = row.get(0);
        //let name =
        class.push(name);
    }

    let result = json!(
    {
    "count": class.len(),
    "class": class
    }
    );

    //let str: String = result.to_string();

    Ok(HttpResponse::build(StatusCode::OK)
        .body(result.to_string()))
}

pub fn article_CLASS_get(req: &HttpRequest<ArcShareState>) -> Result<HttpResponse> {
    let class: String = req.match_info().query("CLASS")?;

    let mut sort: String = "latest".to_string();
    let mut start: i32 = 0;
    let mut len: i32 = 10;

    //获取各个参数
    let query = req.query();
    if let Some(v) = query.get(&"sort".to_string()) {
        //println!("{}", v);
        sort = v.clone();
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    if let Some(v) = query.get(&"start".to_string()) {
        //println!("{}", v);
        start = v.parse().or(Err(error::ErrorBadRequest("")))?;
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    if let Some(v) = query.get(&"len".to_string()) {
        //println!("{}", v);
        len = v.parse().or(Err(error::ErrorBadRequest("")))?;
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    //判断排序方式
    let mut order = "DESC".to_string();
    if sort == "latest" {
        order = "DESC".to_string();
    } else if sort == "oldest" {
        order = "ASC".to_string();
    } else {
        Err(error::ErrorBadRequest(""))?
    }


    //获取数据库连接
    let mut conct = &req.state()
        .lock()
        .or(Err(error::ErrorInternalServerError("mutex error")))?
        .connection;

    let query = format!("\
    SELECT id, title, date, poster, intro, class
    FROM article
    WHERE class = '{}'
    ORDER BY id
    {}
    LIMIT {} OFFSET {}
    ", class, order, len, start);

    //let query = format!(query, order, len, start);

    let mut statement = conct.prepare(&query)
        .or(Err(error::ErrorInternalServerError("prepare error")))?;

    //进行查询
    let rows = statement.query_map(&[], |row| {
        /*
        let id: i64 = row.get(0);
        let title: String = row.get(1);
        let date: i64 = row.get(2);
        let poster: String = row.get(3);
        let intro: String = row.get(4);
        let class: String = row.get(5);

        json!({
            "id": id,
            "title": title,
            "date": date,
            "poster": poster,
            "intro": intro,
            "class": class
        })
        */
        json!({
            "id": row.get::<_, i64>(0),
            "title": row.get::<_, String>(1),
            "date": row.get::<_, i64>(2),
            "poster": row.get::<_, String>(3),
            "intro": row.get::<_, String>(4),
            "class": row.get::<_, String>(5)
        })
    }
    ).or(Err(error::ErrorInternalServerError("query error")))?;

    let mut article_list = vec![];

    //铁代出所有结果
    for r in rows {
        let r = r.or(Err(error::ErrorInternalServerError("")))?;
        article_list.push(r);
    }


    let query = format!("SELECT COUNT(*) FROM article WHERE class = '{}'", class);
    //查询总数
    let total = conct.query_row(&query, &[], |r| r.get::<i32, i32>(0))
        .or(Err(error::ErrorInternalServerError("")))?;

    let result = json!({
        "total": total,
        "count": article_list.len(),
        "article": article_list
    });

    Ok(HttpResponse::build(StatusCode::OK).body(result.to_string()))


    //Ok(format!("article_{}_get", class))
    //"dd"
}

pub fn article_CLASS_post((req, body, class): (HttpRequest<ArcShareState>, String, Path<String>)) -> Result<String> {

    use self::chrono::Local;

    let post_json: serde_json::Value = serde_json::from_str(&body).or(Err(error::ErrorBadRequest("")))?;
    let title = post_json["title"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let intro = post_json["intro"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let content = post_json["content"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let token = post_json["token"].as_str().ok_or(error::ErrorBadRequest(""))?;

    let curtime = Local::now().timestamp();
    let conct = &req.state().lock().
        or(Err(error::ErrorInternalServerError("")))?
        .connection;

    let token_info = dragonpak::check_token(conct, token, curtime)
        .ok_or(error::ErrorUnauthorized(""))?;
    let token_json: serde_json::Value = serde_json::from_str(&token_info).
        or(Err(error::ErrorInternalServerError("")))?;

    let user = token_json["user"].as_str().ok_or(error::ErrorBadRequest(""))?;

    let insert = r#"
    INSERT INTO article VALUES (?, ?, ?, ?, ?, ?, ?)
    "#;

    let infect = conct.execute(insert, &[&curtime, &title, &curtime, &user, &intro, &*class, &content])
        .or(Err(error::ErrorInternalServerError("")))?;

    if infect == 0 {
        Err(error::ErrorInternalServerError(""))?;
    }

    let result = format!(r#"{{"id":{}, "uri":"api/article/{}/{}"}}"#,
        curtime, class, curtime);

    //use std::convert::*;
    /*
    //let req_data = req.body().wait().or(Err(error::ErrorInternalServerError("")))?;
    let payload_stream = req.payload().wait();
    let mut payload_data: Vec<u8> = vec![];

    for t in payload_stream {
        let t = t.or(Err(error::ErrorInternalServerError("")))?;
        payload_data.append(&mut t.to_vec());
    }

    let body = String::from_utf8(payload_data)
        .or(Err(error::ErrorInternalServerError("")))?;
    */
    //let class: String = req.match_info().query("CLASS")?;

    Ok(result)
}

pub fn article_CLASS_ID_get((req, path): (HttpRequest<ArcShareState>, Path<(String, i64)>)) -> Result<String> {
    //let class: String = req.match_info().query("CLASS")?;
    //let id: String = req.match_info().query("ID")?;

    let class = &path.0;
    let id = path.1;

    let query = r#"
    SELECT * from article
    WHERE class = ? AND id = ?
    "#;

    let conct = &req.state().lock()
        .or(Err(error::ErrorInternalServerError("")))?
        .connection;

    let article = conct.query_row(query, &[class, &id], |r| {
        json!({
            "id": r.get::<_, i64>(0),
            "title": r.get::<_, String>(1),
            "date": r.get::<_, i64>(2),
            "poster": r.get::<_, String>(3),
            "intro": r.get::<_, String>(4),
            "class": r.get::<_, String>(5),
            "content": r.get::<_, String>(6)
        })
    }).or(Err(error::ErrorNotFound("")))?;



    Ok(article.to_string())
}

pub fn article_CLASS_ID_delete((req, path, query): (HttpRequest<ArcShareState>, Path<(String, i64)>, Query<HashMap<String, String>>)) -> Result<String> {
    //let class: String = req.match_info().query("CLASS")?;
    //let id: String = req.match_info().query("ID")?;
    use self::chrono::Local;

    let class = &path.0;
    let id = path.1;
    let token = query.get("token").ok_or(error::ErrorBadRequest(""))?;
    let conct = &req.state().lock().or(Err(error::ErrorInternalServerError("")))?
        .connection;
    let curtime = Local::now().timestamp();


    let token_info = dragonpak::check_token(conct, token, curtime)
        .ok_or(error::ErrorUnauthorized(""))?;

    let info_json: serde_json::Value = serde_json::from_str(&token_info)
        .or(Err(error::ErrorInternalServerError("")))?;

    let token_user = info_json["user"].as_str()
        .ok_or(error::ErrorInternalServerError(""))?;

    let db_query = r#"
    SELECT poster FROM article
    WHERE id = ? AND class = ?
    "#;

    let poster: String = conct.query_row(db_query, &[&id, class], |r| r.get(0))
        .or(Err(error::ErrorNotFound("")))?;

    if token_user != poster {
        Err(error::ErrorUnauthorized(""))?;
    }

    let db_delete = r#"
    DELETE FROM article
    WHERE id = ?
    "#;

    let infect = conct.execute(db_delete, &[&id])
        .or(Err(error::ErrorInternalServerError("")))?;

    if infect == 0 {
        Err(error::ErrorInternalServerError(""))?;
    }

    Ok(String::new())
}

pub fn article_CLASS_ID_post((req, path, body): (HttpRequest<ArcShareState>, Path<(String, i64)>, String)) -> Result<String> {
    use self::chrono::Local;

    let class = &path.0;
    let id = path.1;

    let body_json: serde_json::Value = serde_json::from_str(&body)
        .or(Err(error::ErrorBadRequest("")))?;
    let token = body_json["token"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let title = body_json["title"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let intro = body_json["intro"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let content = body_json["content"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let conct = &req.state().lock()
        .or(Err(error::ErrorInternalServerError("")))?.connection;
    let curtime = Local::now().timestamp();

    let token_info = dragonpak::check_token(conct, token, curtime)
        .ok_or(error::ErrorUnauthorized(""))?;
    let info_json: serde_json::Value = serde_json::from_str(&token_info)
        .or(Err(error::ErrorInternalServerError("")))?;
    let token_user = info_json["user"].as_str()
        .ok_or(error::ErrorInternalServerError(""))?;

    let db_query = r#"
    SELECT poster FROM article
    WHERE id = ? AND class = ?
    "#;

    let poster: String = conct.query_row(db_query, &[&id, class], |r| r.get(0))
        .or(Err(error::ErrorNotFound("")))?;
    //验证用户
    if token_user != poster {
        Err(error::ErrorUnauthorized(""))?;
    }

    let db_update = r#"
    UPDATE article
    SET title = ?, intro = ?, content = ?
    WHERE class = ? AND id = ?
    "#;

    let infect = conct.execute(db_update, &[&title, &intro, &content, class, &id])
        .or(Err(error::ErrorInternalServerError("")))?;

    if infect == 0 {
        Err(error::ErrorInternalServerError(""))?;
    }

    //let class: String = req.match_info().query("CLASS")?;
    //let id: String = req.match_info().query("ID")?;
    Ok(format!(r#"{{"id":{}, "uri":"api/article/{}/{}"}}"#, id, class, id))
}


pub fn article_CLASS_ID_IMG_get((req, path): (HttpRequest<ArcShareState>, Path<(String, i64, String)>)) -> Result<NamedFile> {
    //let class: String = req.match_info().query("CLASS")?;
    //let id: String = req.match_info().query("ID")?;
    //let img: String = req.match_info().query("IMG")?;

    let class = &path.0;
    let id = path.1;
    let img = &path.2;

    let url = format!("data/img/article/{}/{}/{}", class, id, img);

    NamedFile::open(url).or(Err(error::ErrorNotFound("")))

    //Ok(NamedFile::open(url))
}


pub fn article_CLASS_ID_IMG_post((req, path, query): (HttpRequest<ArcShareState>, Path<(String, i64, String)>, Query<HashMap<String, String>>)) -> Box<Future<Item = HttpResponse, Error = Error>> {
    use self::actix_web::multipart::{Multipart, MultipartItem};
    //use self::actix_web::error::PayloadError;
    use self::actix_web::Either;
    //use self::actix_web::actix::fut::ok;
    use self::futures::future::{ok, err};
    use self::actix_web::http::StatusCode;
    //use self::actix_web::futures::Stream;
    use self::futures::Stream;
    //use self::actix_web::actix::fut::FinishStream;
    use self::actix_web::AsyncResponder;
    //use self::futures::future::FutureResult;
    //use self::actix_web::actix::fut::helpers;
    //use std::str;
    use std::fs::File;
    use std::io::Write;
    use std::fs::DirBuilder;
    use self::chrono::Local;
    //use self::ser


    let class = path.0.clone();
    let id = path.1;
    let img = path.2.clone();

    //let mut token = String::new();
    let token = match query.get("token").ok_or(error::ErrorBadRequest("")) {
        Ok(t) => {t},
        Err(e) => {return err(e).responder();}
    };

    let conct = &{match req.state().lock() {
        Ok(c) => {c},
        Err(e) => {return err(error::ErrorInternalServerError("")).responder()}
    }}.connection; 
    //let conct = &req.state().lock().or(Err(error::ErrorInternalServerError("")))?
    //    .connection;

    //println!("article_CLASS_ID_IMG_put");
    let curtime = Local::now().timestamp();

    let token_info = match dragonpak::check_token(conct, token, curtime) {
        Some(t) => t,
        None => return err(error::ErrorUnauthorized("")).responder()
    };

    let info_json: serde_json::Value = match serde_json::from_str(&token_info) {
        Ok(j) => j,
        Err(_) => return err(error::ErrorInternalServerError("")).responder()
    };

    let token_user = match info_json["user"].as_str() {
        Some(s) => s.clone(),
        None => return err(error::ErrorInternalServerError("")).responder()
    };

    let db_query = r#"
    SELECT poster FROM article
    WHERE id = ? AND class = ?
    "#;

    let poster: String = match conct.query_row(db_query, &[&id, &class], |r| r.get(0)) {
        Ok(s) => s,
        Err(_) => return err(error::ErrorNotFound("")).responder()      //不存在该id
    };

    if token_user != poster {
        return err(error::ErrorUnauthorized("")).responder()    //用户不匹配
    }

    req.multipart().and_then(move |item| {
        //返回item=Result的future
        let class = class.clone();
        let id = id;
        let img = img.clone();
        println!("get item");
        match item {
            MultipartItem::Field(f) => {
                match f.content_disposition() {
                    Some(ref cd) if {
                        match cd.get_name() {
                            Some(name) => {
                                name == "file_upload"
                            },
                            _ => {false}
                        }
                    } => {
                        Either::A(f.concat2().map(move |bytes| -> Result<_, _> {
                            let path = format!("data/img/article/{}/{}", class, id);
                            let dirbuilder = DirBuilder::new().recursive(true).create(&path)
                                .map_err(|e| "can not create dir")?;
                            let path = format!("{}/{}", path, img);
                            //write data to file
                            let mut file = File::create(path).map_err(|e| "can not open file")?;
                            file.write_all(&bytes).map_err(|e| "can not write to file")?;
                            //println!("data: {:?}", bytes);
                            Ok("")
                        }))
                    },
                    _ => {
                        Either::B(ok(Err("")))
                    }
                }
            },
            MultipartItem::Nested(mp) => {
                Either::B(ok(Err("")))
            }
        }
    })
        .collect()
        .map_err(|e| {
            println!("error : {}", e);
            error::ErrorNotFound("")
        })
        .map(|result: Vec<Result<_, _>>| {

            for i in result {
                match i {
                    Ok(_) => {
                        return HttpResponse::new(StatusCode::OK);
                    },
                    Err(e) => {
                        println!("error : {}", e);
                    }
                }
            }

            HttpResponse::new(StatusCode::NOT_FOUND)
        })
        .responder()

    //Ok(format!("article_{}_{}_{}_put", class, id, img))
    //ok(HttpResponse::new(StatusCode::OK)).responder()
}

// app ===================================================

pub fn app_get(req: &HttpRequest<ArcShareState>) -> Result<String> {

    let mut sort: String = "latest".to_string();
    let mut start: i32 = 0;
    let mut len: i32 = 10;

    //获取各个参数
    let query = req.query();
    if let Some(v) = query.get(&"sort".to_string()) {
        //println!("{}", v);
        sort = v.clone();
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    if let Some(v) = query.get(&"start".to_string()) {
        //println!("{}", v);
        start = v.parse().or(Err(error::ErrorBadRequest("")))?;
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    if let Some(v) = query.get(&"len".to_string()) {
        //println!("{}", v);
        len = v.parse().or(Err(error::ErrorBadRequest("")))?;
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    //判断排序方式
    let mut order = "DESC".to_string();
    if sort == "latest" {
        order = "DESC".to_string();
    } else if sort == "oldest" {
        order = "ASC".to_string();
    } else {
        Err(error::ErrorBadRequest(""))?
    }


    //获取数据库连接
    let mut conct = &req.state()
        .lock()
        .or(Err(error::ErrorInternalServerError("mutex error")))?
        .connection;

    let query = format!("\
    SELECT package, name, intro, icon, date, poster, class
    FROM app
    ORDER BY date
    {}
    LIMIT {} OFFSET {}
    ", order, len, start);

    //let query = format!(query, order, len, start);

    let mut statement = conct.prepare(&query)
        .or(Err(error::ErrorInternalServerError("prepare error")))?;

    //进行查询
    let rows = statement.query_map(&[], |row| {
        /*
        let id: i64 = row.get(0);
        let title: String = row.get(1);
        let date: i64 = row.get(2);
        let poster: String = row.get(3);
        let intro: String = row.get(4);
        let class: String = row.get(5);

        json!({
            "id": id,
            "title": title,
            "date": date,
            "poster": poster,
            "intro": intro,
            "class": class
        })
        */
        json!({
            "package": row.get::<_, String>(0),
            "name": row.get::<_, String>(1),
            "intro": row.get::<_, String>(2),
            "icon": row.get::<_, String>(3),
            "date": row.get::<_, i64>(4),
            "poster": row.get::<_, String>(5),
            "class": row.get::<_, String>(6)
        })
    }
    ).or(Err(error::ErrorInternalServerError("query error")))?;

    let mut app_list = vec![];

    //铁代出所有结果
    for r in rows {
        let r = r.or(Err(error::ErrorInternalServerError("")))?;
        app_list.push(r);
    }


    let query = "SELECT COUNT(*) FROM app";
    //查询总数
    let total = conct.query_row(query, &[], |r| r.get::<_, i32>(0))
        .or(Err(error::ErrorInternalServerError("")))?;

    let result = json!({
        "total": total,
        "count": app_list.len(),
        "app": app_list
    });

    //Ok(HttpResponse::build(StatusCode::OK).body(result.to_string()))


    Ok(result.to_string())
}

pub fn app_class_get(req: &HttpRequest<ArcShareState>) -> Result<String> {

    let mut conct = &req.state()
        .lock()
        .or(Err(error::ErrorInternalServerError("mutex error")))?
        .connection;


    let query = "\
    SELECT * FROM app_class
    ";

    let mut statement = conct.prepare(query)
        .or(Err(error::ErrorInternalServerError("prepare error")))?;
    let rows = statement.query_map(&[], |row| row.get(0))
        .or(Err(error::ErrorInternalServerError("query error")))?;

    let mut class = vec![];

    for t in rows {
        let name: String = t.or(Err(error::ErrorInternalServerError("get data error")))?;
        //let name: String = row.get(0);
        //let name =
        class.push(name);
    }

    let result = json!(
    {
    "count": class.len(),
    "class": class
    }
    );

    //let str: String = result.to_string();

    Ok(result.to_string())
}


pub fn app_CLASS_get(req: &HttpRequest<ArcShareState>) -> Result<String> {

    let class: String = req.match_info().query("CLASS")?;

    let mut sort: String = "latest".to_string();
    let mut start: i32 = 0;
    let mut len: i32 = 10;

    //获取各个参数
    let query = req.query();
    if let Some(v) = query.get(&"sort".to_string()) {
        //println!("{}", v);
        sort = v.clone();
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    if let Some(v) = query.get(&"start".to_string()) {
        //println!("{}", v);
        start = v.parse().or(Err(error::ErrorBadRequest("")))?;
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    if let Some(v) = query.get(&"len".to_string()) {
        //println!("{}", v);
        len = v.parse().or(Err(error::ErrorBadRequest("")))?;
    } else {
        Err(error::ErrorBadRequest(""))?
    }

    //判断排序方式
    let mut order = "DESC".to_string();
    if sort == "latest" {
        order = "DESC".to_string();
    } else if sort == "oldest" {
        order = "ASC".to_string();
    } else {
        Err(error::ErrorBadRequest(""))?
    }


    //获取数据库连接
    let mut conct = &req.state()
        .lock()
        .or(Err(error::ErrorInternalServerError("mutex error")))?
        .connection;

    let query = format!("\
    SELECT package, name, intro, icon, date, poster, class
    FROM app
    WHERE class = '{}'
    ORDER BY date
    {}
    LIMIT {} OFFSET {}
    ", class, order, len, start);

    //let query = format!(query, order, len, start);

    let mut statement = conct.prepare(&query)
        .or(Err(error::ErrorInternalServerError("prepare error")))?;

    //进行查询
    let rows = statement.query_map(&[], |row| {
        /*
        let id: i64 = row.get(0);
        let title: String = row.get(1);
        let date: i64 = row.get(2);
        let poster: String = row.get(3);
        let intro: String = row.get(4);
        let class: String = row.get(5);

        json!({
            "id": id,
            "title": title,
            "date": date,
            "poster": poster,
            "intro": intro,
            "class": class
        })
        */
        json!({
            "package": row.get::<_, String>(0),
            "name": row.get::<_, String>(1),
            "intro": row.get::<_, String>(2),
            "icon": row.get::<_, String>(3),
            "date": row.get::<_, i64>(4),
            "poster": row.get::<_, String>(5),
            "class": row.get::<_, String>(6)
        })
    }
    ).or(Err(error::ErrorInternalServerError("query error")))?;

    let mut app_list = vec![];

    //铁代出所有结果
    for r in rows {
        let r = r.or(Err(error::ErrorInternalServerError("")))?;
        app_list.push(r);
    }


    let query = format!("SELECT COUNT(*) FROM app WHERE class = '{}'", class);
    //查询总数
    let total = conct.query_row(&query, &[], |r| r.get::<i32, i32>(0))
        .or(Err(error::ErrorInternalServerError("")))?;

    let result = json!({
        "total": total,
        "count": app_list.len(),
        "article": app_list
    });

    //Ok(HttpResponse::build(StatusCode::OK).body(result.to_string()))


    Ok(result.to_string())
}


pub fn app_CLASS_post((req, body, class): (HttpRequest<ArcShareState>, String, Path<String>)) -> Result<String> {


    use self::chrono::Local;

    let post_json: serde_json::Value = serde_json::from_str(&body).or(Err(error::ErrorBadRequest("")))?;
    //let title = post_json["title"].as_str().ok_or(error::ErrorBadRequest(""))?;
    //let intro = post_json["intro"].as_str().ok_or(error::ErrorBadRequest(""))?;
    //let content = post_json["content"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let name = post_json["name"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let package = post_json["package"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let intro = post_json["intro"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let icon = post_json["icon"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let content = post_json["content"].as_str().ok_or(error::ErrorBadRequest(""))?;

    let token = post_json["token"].as_str().ok_or(error::ErrorBadRequest(""))?;

    let curtime = Local::now().timestamp();
    let conct = &req.state().lock().
        or(Err(error::ErrorInternalServerError("")))?
        .connection;

    let token_info = dragonpak::check_token(conct, token, curtime)
        .ok_or(error::ErrorUnauthorized(""))?;
    let token_json: serde_json::Value = serde_json::from_str(&token_info).
        or(Err(error::ErrorInternalServerError("")))?;

    let user = token_json["user"].as_str().ok_or(error::ErrorBadRequest(""))?;

    let insert = r#"
    INSERT INTO app VALUES (?, ?, ?, ?, ?, ?, ?, ?)
    "#;

    let infect = conct.execute(insert, &[&package, &name, &intro, &icon, &curtime, &user, &*class, &content])
        .or(Err(error::ErrorInternalServerError("")))?;

    if infect == 0 {
        Err(error::ErrorInternalServerError(""))?;
    }


    //let result = format!(r#"{{"id":{}, "uri":"api/article/{}/{}"}}"#,
    //                     curtime, class, curtime);

    Ok(String::new())

    //Ok(String::from("app get"))
}



pub fn app_CLASS_ID_get((req, path): (HttpRequest<ArcShareState>, Path<(String, String)>)) -> Result<String> {
    let class = &path.0;
    let package = &path.1;

    let query = r#"
    SELECT * from app
    WHERE class = ? AND package = ?
    "#;

    let conct = &req.state().lock()
        .or(Err(error::ErrorInternalServerError("")))?
        .connection;

    let article = conct.query_row(query, &[class, package], |r| {
        json!({
            "package": r.get::<_, String>(0),
            "name": r.get::<_, String>(1),
            "intro": r.get::<_, String>(2),
            "icon": r.get::<_, String>(3),
            "date": r.get::<_, i64>(4),
            "poster": r.get::<_, String>(5),
            "class": r.get::<_, String>(6),
            "content": r.get::<_, String>(7)
        })
    }).or(Err(error::ErrorNotFound("")))?;



    Ok(article.to_string())

    //Ok(String::from("app get"))
}



pub fn app_CLASS_ID_post((req, path, body): (HttpRequest<ArcShareState>, Path<(String, String)>, String)) -> Result<String> {

    use self::chrono::Local;

    let class = &path.0;
    let package = &path.1;

    let body_json: serde_json::Value = serde_json::from_str(&body)
        .or(Err(error::ErrorBadRequest("")))?;
    let token = body_json["token"].as_str().ok_or(error::ErrorBadRequest(""))?;
    //let title = body_json["title"].as_str().ok_or(error::ErrorBadRequest(""))?;
    //let intro = body_json["intro"].as_str().ok_or(error::ErrorBadRequest(""))?;
    //let content = body_json["content"].as_str().ok_or(error::ErrorBadRequest(""))?;

    let name = body_json["name"].as_str().ok_or(error::ErrorBadRequest(""))?;
    //let package = body_json["package"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let intro = body_json["intro"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let icon = body_json["icon"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let content = body_json["content"].as_str().ok_or(error::ErrorBadRequest(""))?;

    let conct = &req.state().lock()
        .or(Err(error::ErrorInternalServerError("")))?.connection;
    let curtime = Local::now().timestamp();

    let token_info = dragonpak::check_token(conct, token, curtime)
        .ok_or(error::ErrorUnauthorized(""))?;
    let info_json: serde_json::Value = serde_json::from_str(&token_info)
        .or(Err(error::ErrorInternalServerError("")))?;
    let token_user = info_json["user"].as_str()
        .ok_or(error::ErrorInternalServerError(""))?;

    let db_query = r#"
    SELECT poster FROM app
    WHERE package = ? AND class = ?
    "#;

    let poster: String = conct.query_row(db_query, &[package, class], |r| r.get(0))
        .or(Err(error::ErrorNotFound("")))?;
    //验证用户
    if token_user != poster {
        Err(error::ErrorUnauthorized(""))?;
    }

    let db_update = r#"
    UPDATE app
    SET name = ?, intro = ?,
        icon = ?, date = ?, poster = ?,
        class = ?, content = ?
    WHERE class = ? AND package = ?
    "#;

    let infect = conct.execute(db_update, &[
            &name, &intro, &icon,
            &curtime, &poster, class, &content,
            class, package])
        .or(Err(error::ErrorInternalServerError("")))?;

    if infect == 0 {
        Err(error::ErrorInternalServerError(""))?;
    }

    //let class: String = req.match_info().query("CLASS")?;
    //let id: String = req.match_info().query("ID")?;
    //Ok(format!(r#"{{"id":{}, "uri":"api/article/{}/{}"}}"#, id, class, id))

    Ok(String::new())
}


pub fn app_CLASS_ID_delete((req, path, query): (HttpRequest<ArcShareState>, Path<(String, String)>, Query<HashMap<String, String>>)) -> Result<String> {

    use self::chrono::Local;

    let class = &path.0;
    let package = &path.1;
    let token = query.get("token").ok_or(error::ErrorBadRequest(""))?;
    let conct = &req.state().lock().or(Err(error::ErrorInternalServerError("")))?
        .connection;
    let curtime = Local::now().timestamp();


    let token_info = dragonpak::check_token(conct, token, curtime)
        .ok_or(error::ErrorUnauthorized(""))?;

    let info_json: serde_json::Value = serde_json::from_str(&token_info)
        .or(Err(error::ErrorInternalServerError("")))?;

    let token_user = info_json["user"].as_str()
        .ok_or(error::ErrorInternalServerError(""))?;

    let db_query = r#"
    SELECT poster FROM app
    WHERE package = ? AND class = ?
    "#;

    let poster: String = conct.query_row(db_query, &[package, class], |r| r.get(0))
        .or(Err(error::ErrorNotFound("")))?;

    if token_user != poster {
        Err(error::ErrorUnauthorized(""))?;
    }

    let db_delete = r#"
    DELETE FROM app
    WHERE package = ? AND class = ?
    "#;

    let infect = conct.execute(db_delete, &[package, class])
        .or(Err(error::ErrorInternalServerError("")))?;

    if infect == 0 {
        Err(error::ErrorInternalServerError(""))?;
    }

    Ok(String::new())


    //Ok(String::from("app get"))
}

pub fn app_CLASS_ID_IMG_get((req, path): (HttpRequest<ArcShareState>, Path<(String, i64, String)>)) -> Result<NamedFile> {
    let class = &path.0;
    let id = path.1;
    let img = &path.2;

    let url = format!("data/img/app/{}/{}/{}", class, id, img);

    NamedFile::open(url).or(Err(error::ErrorNotFound("")))
}


pub fn app_CLASS_ID_IMG_post((req, path, query): (HttpRequest<ArcShareState>, Path<(String, String, String)>, Query<HashMap<String, String>>)) -> Box<Future<Item = HttpResponse, Error = Error>> {
    use self::actix_web::multipart::{Multipart, MultipartItem};
    //use self::actix_web::error::PayloadError;
    use self::actix_web::Either;
    //use self::actix_web::actix::fut::ok;
    use self::futures::future::{ok, err};
    use self::actix_web::http::StatusCode;
    //use self::actix_web::futures::Stream;
    use self::futures::Stream;
    //use self::actix_web::actix::fut::FinishStream;
    use self::actix_web::AsyncResponder;
    //use self::futures::future::FutureResult;
    //use self::actix_web::actix::fut::helpers;
    //use std::str;
    use std::fs::File;
    use std::io::Write;
    use std::fs::DirBuilder;
    use self::chrono::Local;
    //use self::ser


    let class = path.0.clone();
    let id = path.1.clone();
    let img = path.2.clone();

    //let mut token = String::new();
    let token = match query.get("token").ok_or(error::ErrorBadRequest("")) {
        Ok(t) => {t},
        Err(e) => {return err(e).responder();}
    };

    let conct = &{match req.state().lock() {
        Ok(c) => {c},
        Err(e) => {return err(error::ErrorInternalServerError("")).responder()}
    }}.connection; 
    //let conct = &req.state().lock().or(Err(error::ErrorInternalServerError("")))?
    //    .connection;

    //println!("article_CLASS_ID_IMG_put");
    let curtime = Local::now().timestamp();

    let token_info = match dragonpak::check_token(conct, token, curtime) {
        Some(t) => t,
        None => return err(error::ErrorUnauthorized("")).responder()
    };

    let info_json: serde_json::Value = match serde_json::from_str(&token_info) {
        Ok(j) => j,
        Err(_) => return err(error::ErrorInternalServerError("")).responder()
    };

    let token_user = match info_json["user"].as_str() {
        Some(s) => s.clone(),
        None => return err(error::ErrorInternalServerError("")).responder()
    };

    let db_query = r#"
    SELECT poster FROM app
    WHERE package = ? AND class = ?
    "#;

    let poster: String = match conct.query_row(db_query, &[&id, &class], |r| r.get(0)) {
        Ok(s) => s,
        Err(_) => return err(error::ErrorNotFound("")).responder()      //不存在该id
    };

    if token_user != poster {
        return err(error::ErrorUnauthorized("")).responder()    //用户不匹配
    }

    req.multipart().and_then(move |item| {
        //返回item=Result的future
        let class = class.clone();
        let id = id.clone();
        let img = img.clone();
        println!("get item");
        match item {
            MultipartItem::Field(f) => {
                match f.content_disposition() {
                    Some(ref cd) if {
                        match cd.get_name() {
                            Some(name) => {
                                name == "file_upload"
                            },
                            _ => {false}
                        }
                    } => {
                        Either::A(f.concat2().map(move |bytes| -> Result<_, _> {
                            let path = format!("data/img/app/{}/{}", class, id);
                            let dirbuilder = DirBuilder::new().recursive(true).create(&path)
                                .map_err(|e| "can not create dir")?;
                            let path = format!("{}/{}", path, img);
                            //write data to file
                            let mut file = File::create(path).map_err(|e| "can not open file")?;
                            file.write_all(&bytes).map_err(|e| "can not write to file")?;
                            //println!("data: {:?}", bytes);
                            Ok("")
                        }))
                    },
                    _ => {
                        Either::B(ok(Err("")))
                    }
                }
            },
            MultipartItem::Nested(mp) => {
                Either::B(ok(Err("")))
            }
        }
    })
        .collect()
        .map_err(|e| {
            println!("error : {}", e);
            error::ErrorNotFound("")
        })
        .map(|result: Vec<Result<_, _>>| {

            for i in result {
                match i {
                    Ok(_) => {
                        return HttpResponse::new(StatusCode::OK);
                    },
                    Err(e) => {
                        println!("error : {}", e);
                    }
                }
            }

            HttpResponse::new(StatusCode::NOT_FOUND)
        })
        .responder()
}


// user =======================================

pub fn user_post((req, data): (HttpRequest<ArcShareState>, String)) -> Result<String> {

    use self::chrono::Local;
    use self::rand::prelude::*;
    let curtime = Local::now().timestamp();

    let post_json: serde_json::Value = serde_json::from_str(&data)
        .or(Err(error::ErrorBadRequest("")))?;

    let password = post_json["password"].as_str().ok_or(error::ErrorBadRequest(""))?;
    let user_id = post_json["id"].as_str().ok_or(error::ErrorBadRequest(""))?;

    let db_query = r#"
    SELECT * FROM user
    WHERE id = ? AND password = ?
    "#;

    let conct = &req.state().lock().or(Err(error::ErrorInternalServerError("")))?.connection;

    //clear time out login
    dragonpak::clear_token(conct, curtime).or(Err(error::ErrorInternalServerError("")))?;

    let mut statement = conct.prepare(db_query).or(Err(error::ErrorInternalServerError("")))?;
    let exists = statement.exists(&[&user_id, &password]).or(Err(error::ErrorInternalServerError("")))?;
    if !exists {
        return Err(error::ErrorUnauthorized(""));
    }

    
    let random_num: i64 = random();

    let info = json!({
        "user": user_id,
        "create_date": curtime,
        "timeout": curtime + 86400,
        "random": random_num
    });

    let info = info.to_string();

    let token = dragonpak::add_token(conct, &info, curtime + 86400).or(Err(error::ErrorUnauthorized("")))?;

    let result = json!({
        "token": token
    });

    Ok(result.to_string())
}


pub fn user_delete((req, query): (HttpRequest<ArcShareState>, Query<HashMap<String, String>>)) -> Result<String> {
    
    let token = query.get("token").ok_or(error::ErrorBadRequest(""))?;
    let conct = &req.state().lock().or(Err(error::ErrorInternalServerError("")))?.connection;

    let db_delete = r#"
    DELETE FROM token
    WHERE token = ?
    "#;

    let delete_num = conct.execute(db_delete, &[token]).or(Err(error::ErrorInternalServerError("")))?;

    Ok(String::new())
}

pub fn user_get((req, query): (HttpRequest<ArcShareState>, Query<HashMap<String, String>>)) -> Result<String> {
    use self::chrono::Local;

    let token = query.get("token").ok_or(error::ErrorBadRequest(""))?;
    let conct = &req.state().lock().or(Err(error::ErrorInternalServerError("")))?.connection;

    let curtime = Local::now().timestamp();

    let token_info = dragonpak::check_token(conct, token, curtime).ok_or(error::ErrorUnauthorized(""))?;
    let info_json: serde_json::Value = serde_json::from_str(&token_info).or(Err(error::ErrorInternalServerError("")))?;
    let user_id = info_json["user"].as_str().ok_or(error::ErrorInternalServerError(""))?;

    let result = json!({
        "id": user_id
    });

    Ok(result.to_string())
}